﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.FileDataSource
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Threading;

namespace Microsoft.InfoCards
{
  internal class FileDataSource : DataSource
  {
    private static readonly SecurityIdentifier AdministratorSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, (SecurityIdentifier) null);
    private int m_variableSignatureLength = 64;
    public const int ENCRYPTIONKEYBUFFERSIZE = 32;
    public const int ENCRYPTIONKEYBITLENGTH = 256;
    public const int ENCRYPTIONBLOCKBUFFERSIZE = 16;
    public const int ENCRYPTIONBLOCKBITLENGTH = 128;
    public const int ENCRYPTIONITERATIONS = 1000;
    public const int INITIALINDEXITEMCOUNT = 20;
    public const int INITIALINDEXAREASIZE = 80;
    public const int INITIALBLOBAREASIZE = 2048;
    public const int FILEVERSION = 11;
    public const int FILEVERSIONV2 = 12;
    private FileInfo m_fileInfo;
    private FileStream m_file;
    private FileInfo m_shadowInfo;
    private FileStream m_shadow;
    private byte[] m_header;
    private IndexedDataBuffer m_data;
    private SecondaryIndexList m_indexes;
    private ReaderWriterLock m_lock;
    private SymmetricAlgorithm m_encAlg;
    private byte[] m_key;
    private bool m_keyProtected;
    private WindowsIdentity m_identity;
    private bool m_currentTransactionDirty;
    private SafeRsaProviderHandle m_provider;
    private byte[] m_encryptedKey;

    protected FileDataSource()
      : base((string) null, (string) null)
    {
    }

    public FileDataSource(WindowsIdentity identity, string fileName)
      : this(identity, fileName, Guid.NewGuid().ToString("P"), SecondaryIndexDefinition.MasterIndexes)
    {
    }

    public FileDataSource(
      WindowsIdentity identity,
      string fileName,
      string instanceId,
      SecondaryIndexDefinition[] indexDefinitions)
      : base(instanceId, fileName)
    {
      this.m_identity = identity;
      this.m_currentTransactionDirty = false;
      this.m_fileInfo = new FileInfo(fileName);
      this.m_shadowInfo = new FileInfo(this.m_fileInfo.FullName + ".shadow");
      this.m_lock = new ReaderWriterLock();
      this.m_indexes = new SecondaryIndexList(indexDefinitions);
      this.m_encAlg = FileDataSource.CreateEncryptionAlg();
      this.SetupProvider();
    }

    public IndexedDataBuffer Buffer
    {
      get
      {
        this.ThrowIfDisposed();
        this.ThrowIfNotLoaded();
        return this.m_data;
      }
    }

    public byte[] Header
    {
      get
      {
        this.ThrowIfDisposed();
        this.ThrowIfNotLoaded();
        return this.m_header;
      }
    }

    public SecondaryIndexList Indexes
    {
      get
      {
        this.ThrowIfDisposed();
        this.ThrowIfNotLoaded();
        return this.m_indexes;
      }
    }

    protected WindowsIdentity Identity
    {
      get
      {
        return this.m_identity;
      }
    }

    protected internal override void OnClear()
    {
      using (new SystemIdentity(true))
      {
        FileDataSource.ResilientDelete(this.m_fileInfo);
        FileDataSource.ResilientDelete(this.m_shadowInfo);
      }
    }

    protected internal override void OnLoad()
    {
      this.ThrowIfDisposed();
      try
      {
        this.CreateDirAndFiles();
        if (this.m_shadow.Length > 0L)
        {
          if (this.m_file.Length > 0L)
          {
            this.m_shadow.SetLength(0L);
            this.LoadFrom((Stream) this.m_file);
          }
          else
          {
            this.LoadFrom((Stream) this.m_shadow);
            this.FlushToShadow();
            this.SwapFileWithShadow();
          }
        }
        else if (this.m_file.Length > 0L)
        {
          this.LoadFrom((Stream) this.m_file);
        }
        else
        {
          this.CreateEmptyStore();
          this.FlushToShadow();
          this.SwapFileWithShadow();
        }
        this.m_file.Seek(0L, SeekOrigin.Begin);
      }
      catch
      {
        this.CloseFiles();
        throw;
      }
    }

    private void CloseFiles()
    {
      using (new SystemIdentity(false))
      {
        if (this.m_file != null)
        {
          this.m_file.Close();
          this.m_file = (FileStream) null;
        }
        if (this.m_shadow == null)
          return;
        this.m_shadow.Close();
        this.m_shadow = (FileStream) null;
      }
    }

    protected void CreateDirAndFiles()
    {
      this.CheckReparsePoints();
      if (NativeMcppMethods.PathSupportsPersistedSecurity(this.m_fileInfo.Directory.FullName))
        this.ValidateDirectoryAccess();
      using (new SystemIdentity(true))
      {
        try
        {
          if (!this.m_fileInfo.Directory.Exists)
          {
            try
            {
              if (NativeMcppMethods.PathSupportsPersistedSecurity(this.m_fileInfo.Directory.FullName))
                this.m_fileInfo.Directory.Create(FileDataSource.CreateSecurityDescriptor<DirectorySecurity>());
              else
                this.m_fileInfo.Directory.Create();
              this.m_fileInfo.Directory.Attributes |= FileAttributes.Hidden | FileAttributes.NotContentIndexed;
            }
            catch (UnauthorizedAccessException ex)
            {
              throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(ex.Message));
            }
          }
          else if (NativeMcppMethods.PathSupportsPersistedSecurity(this.m_fileInfo.Directory.FullName) && this.LogIfAclsTampered((FileSystemInfo) this.m_fileInfo.Directory))
            this.m_fileInfo.Directory.SetAccessControl(FileDataSource.CreateSecurityDescriptor<DirectorySecurity>());
          InfoCardTrace.Assert(this.m_shadowInfo.Directory.Exists, "m_shadowInfo directory should be same as main directory");
          this.OpenOrCreateHelper(this.m_fileInfo, out this.m_file);
          this.OpenOrCreateHelper(this.m_shadowInfo, out this.m_shadow);
        }
        catch (IOException ex)
        {
          throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(ex.Message));
        }
      }
    }

    private void CheckReparsePoints()
    {
      using (new SystemIdentity(true))
      {
        for (DirectoryInfo directoryInfo = this.m_fileInfo.Directory; directoryInfo != null; directoryInfo = directoryInfo.Parent)
        {
          if (directoryInfo.Exists && (directoryInfo.Attributes & FileAttributes.ReparsePoint) != (FileAttributes) 0)
            throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreNoReparsePointAllowed")));
        }
        if (Directory.Exists(this.m_fileInfo.FullName) && (this.m_fileInfo.Attributes & FileAttributes.ReparsePoint) != (FileAttributes) 0)
          throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreNoReparsePointAllowed")));
      }
    }

    private void ValidateDirectoryAccess()
    {
      InfoCardTrace.Assert(!WindowsIdentity.GetCurrent().IsSystem, "Should not be running as system");
      IdentityReference identityReference = WindowsIdentity.GetCurrent().User.Translate(typeof (NTAccount));
      bool flag = false;
      DirectoryInfo parent = this.m_fileInfo.Directory.Parent;
      if (parent.Exists)
      {
        foreach (FileSystemAccessRule accessRule in (ReadOnlyCollectionBase) parent.GetAccessControl().GetAccessRules(true, true, typeof (NTAccount)))
        {
          if (accessRule.IdentityReference == identityReference && accessRule.FileSystemRights == FileSystemRights.FullControl && accessRule.AccessControlType == AccessControlType.Allow)
          {
            flag = true;
            break;
          }
        }
      }
      if (!flag)
        throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreInvalidDataFilePath")));
    }

    private void OpenOrCreateHelper(FileInfo theFile, out FileStream fileStream)
    {
      InfoCardTrace.Assert(WindowsIdentity.GetCurrent().IsSystem, "Should be running as system");
      if (!File.Exists(theFile.FullName))
      {
        fileStream = FileDataSource.ResilientOpen(theFile, FileMode.CreateNew, FileAccess.ReadWrite);
        theFile.Attributes |= FileAttributes.Hidden | FileAttributes.NotContentIndexed;
        theFile.SetAccessControl(FileDataSource.CreateSecurityDescriptor<FileSecurity>());
      }
      else
      {
        if (NativeMcppMethods.PathSupportsPersistedSecurity(this.m_fileInfo.Directory.FullName) && this.LogIfAclsTampered((FileSystemInfo) theFile))
        {
          theFile.SetAccessControl(FileDataSource.CreateSecurityDescriptor<FileSecurity>());
          theFile.Attributes |= FileAttributes.Hidden | FileAttributes.NotContentIndexed;
        }
        fileStream = FileDataSource.ResilientOpen(theFile, FileMode.Open, FileAccess.ReadWrite);
      }
    }

    protected virtual void OnSwapFileWithShadow()
    {
      using (new SystemIdentity(true))
      {
        string fullName = this.m_fileInfo.FullName;
        FileDataSource.ResilientDelete(this.m_fileInfo);
        FileDataSource.ResilientMove(this.m_shadowInfo, this.m_fileInfo);
        this.m_fileInfo = new FileInfo(fullName);
        this.m_shadowInfo = new FileInfo(fullName + ".shadow");
      }
    }

    protected internal override void OnClose()
    {
      this.ThrowIfDisposed();
      if (this.m_data != null)
      {
        this.m_data.Close();
        this.m_data = (IndexedDataBuffer) null;
      }
      this.m_indexes.Close();
      this.CloseFiles();
      this.m_provider.Dispose();
    }

    protected internal override DataRow ReadRow(int localId, QueryDetails details)
    {
      DataRow row = (DataRow) null;
      if (QueryDetails.Header == (details & QueryDetails.Header))
      {
        row = this.m_data.CreateDataRow(localId);
        if (QueryDetails.DataBlob == (details & QueryDetails.DataBlob))
        {
          byte[] iv = this.AllocateIvBuffer();
          this.m_data.CopyIVFromObject(localId, iv, 0);
          using (Stream streamForObjectData = this.m_data.GetStreamForObjectData(localId))
          {
            using (MemoryStream memoryStream = new MemoryStream((int) streamForObjectData.Length))
            {
              this.DecryptData(iv, streamForObjectData, (Stream) memoryStream);
              row.SetDataField(memoryStream.ToArray());
              byte[] buffer = memoryStream.GetBuffer();
              Array.Clear((Array) buffer, 0, buffer.Length);
            }
          }
        }
        if (QueryDetails.IndexData == (details & QueryDetails.IndexData))
          this.m_indexes.PopulateRowIndexBuffer(row);
      }
      return row;
    }

    protected internal override bool SingleMatch(QueryParameter match, LocalIdCollection localIds)
    {
      this.ThrowIfDisposed();
      this.ThrowIfNotLoaded();
      if (localIds == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (localIds));
      if (match == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (match));
      if (string.IsNullOrEmpty(match.IndexName))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentException(SR.GetString("StoreDataSourceInvalidIndexName", (object) match.IndexName), nameof (match)));
      bool flag = false;
      try
      {
        try
        {
        }
        finally
        {
          this.m_lock.AcquireReaderLock(0);
          flag = true;
        }
        return this.m_indexes.Match(match, localIds);
      }
      finally
      {
        if (flag)
          this.m_lock.ReleaseReaderLock();
      }
    }

    protected internal override void OnBeginTransaction()
    {
      InfoCardTrace.Assert(!this.m_currentTransactionDirty, "m_currentTransactionDirty should have been set to false before beginning a transaction");
      base.OnBeginTransaction();
    }

    protected internal override void OnRollbackTransaction()
    {
      try
      {
        base.OnRollbackTransaction();
        this.LoadFrom((Stream) this.m_file);
      }
      finally
      {
        this.m_currentTransactionDirty = false;
      }
    }

    protected internal override void OnCommitTransaction()
    {
      try
      {
        base.OnCommitTransaction();
        if (!this.m_currentTransactionDirty)
          return;
        this.FlushToShadow();
        this.SwapFileWithShadow();
      }
      finally
      {
        this.m_currentTransactionDirty = false;
      }
    }

    protected internal override void WriteRow(DataRow row)
    {
      this.ThrowIfDisposed();
      this.ThrowIfNotLoaded();
      this.ThrowIfWriteLockNotHeld();
      if (row == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (row));
      bool flag = false;
      try
      {
        try
        {
        }
        finally
        {
          this.m_lock.AcquireWriterLock(0);
          flag = true;
        }
        using (MemoryStream memoryStream1 = new MemoryStream())
        {
          this.m_encAlg.GenerateIV();
          byte[] iv = this.m_encAlg.IV;
          using (MemoryStream memoryStream2 = new MemoryStream(row.GetDataField()))
          {
            this.EncryptData(iv, (Stream) memoryStream2, (Stream) memoryStream1);
            int localId = this.m_data.WriteObject(row.LocalId, iv, memoryStream1.ToArray(), row.ObjectType, row.LastChange, row.GlobalId);
            this.m_indexes.SetValuesForId(localId, row.IndexBuffer, true);
            row.SourceId = this.SourceId;
            row.InstanceId = this.InstanceId;
            row.LocalId = localId;
          }
        }
      }
      finally
      {
        if (flag)
          this.m_lock.ReleaseWriterLock();
      }
      this.m_currentTransactionDirty = true;
    }

    protected internal override void RemoveObject(int id)
    {
      if ((uint) id > (uint) (this.m_data.Index.Length / 4 - 1))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (id), (object) id, SR.GetString("StoreDataSourceIdOutOfRange")));
      bool flag = false;
      try
      {
        try
        {
        }
        finally
        {
          this.m_lock.AcquireWriterLock(0);
          flag = true;
        }
        this.m_data.RemoveObject(id);
        this.m_indexes.RemoveAllValuesForId(id);
      }
      finally
      {
        if (flag)
          this.m_lock.ReleaseWriterLock();
      }
      this.m_currentTransactionDirty = true;
    }

    private void ProtectKey()
    {
      if (this.m_keyProtected)
        throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreKeyAlreadyProtected")));
      ProtectedMemory.Protect(this.m_key, MemoryProtectionScope.SameProcess);
      this.m_keyProtected = true;
    }

    private void UnprotectKey()
    {
      if (!this.m_keyProtected)
        throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreKeyNotAlreadyProtected")));
      ProtectedMemory.Unprotect(this.m_key, MemoryProtectionScope.SameProcess);
      this.m_keyProtected = false;
    }

    private unsafe void DecryptData(byte[] iv, Stream input, Stream output)
    {
      InfoCardTrace.Assert(input is MemoryStream, "Invalid stream type");
      if (iv == null || iv.Length == 0)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (iv));
      if (input == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (input));
      if (output == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (output));
      using (SafeCryptoKey safeCryptoKey = new SafeCryptoKey(this.m_provider, this.m_key, iv))
      {
        byte[] buffer = new byte[input.Length];
        input.Seek(0L, SeekOrigin.Begin);
        input.Read(buffer, 0, (int) input.Length);
        uint length = (uint) buffer.Length;
        fixed (byte* numPtr = &buffer[0])
        {
          if (!NativeMethods.CryptDecrypt(safeCryptoKey.Handle, IntPtr.Zero, 1U, 0U, (IntPtr) ((void*) numPtr), ref length))
          {
            Exception e = (Exception) new Win32Exception(Marshal.GetLastWin32Error());
            Array.Clear((Array) buffer, 0, buffer.Length);
            InfoCardTrace.TraceAndLogException(e);
            throw InfoCardTrace.ThrowHelperError(e);
          }
        }
        output.Write(buffer, 0, (int) length);
      }
    }

    private unsafe void EncryptData(byte[] iv, Stream input, Stream output)
    {
      if (iv == null || iv.Length == 0)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (iv));
      if (input == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (input));
      if (output == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (output));
      using (SafeCryptoKey safeCryptoKey = new SafeCryptoKey(this.m_provider, this.m_key, iv))
      {
        byte[] buffer = new byte[input.Length + (long) this.m_key.Length];
        input.Seek(0L, SeekOrigin.Begin);
        input.Read(buffer, 0, (int) input.Length);
        uint length = (uint) input.Length;
        fixed (byte* numPtr = &buffer[0])
        {
          if (!NativeMethods.CryptEncrypt(safeCryptoKey.Handle, IntPtr.Zero, 1U, 0U, (IntPtr) ((void*) numPtr), ref length, (uint) buffer.Length))
          {
            Exception e = (Exception) new Win32Exception(Marshal.GetLastWin32Error());
            InfoCardTrace.TraceAndLogException(e);
            throw InfoCardTrace.ThrowHelperError(e);
          }
        }
        output.Write(buffer, 0, (int) length);
      }
    }

    private unsafe void CreateEmptyStore()
    {
      this.m_data = new IndexedDataBuffer(new byte[80], new byte[2048], 0, (DataSource) this);
      this.m_encAlg.GenerateKey();
      this.m_key = new byte[this.m_encAlg.Key.Length];
      Array.Copy((Array) this.m_encAlg.Key, 0, (Array) this.m_key, 0, this.m_encAlg.Key.Length);
      this.m_encAlg.GenerateKey();
      this.m_keyProtected = false;
      this.ProtectKey();
      this.m_header = new byte[this.GetTotalHeaderSize()];
      fixed (byte* numPtr = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
        ((EncryptedFileStoreHeader*) numPtr)->Version = 12U;
      this.EncryptAndSaveDPAPIKeyToHeader();
    }

    private void FlushToShadow()
    {
      this.FlushToStream((Stream) this.m_shadow);
    }

    private int GetTotalHeaderSize()
    {
      return sizeof (EncryptedFileStoreHeader) + this.GetTotalSignatureSize();
    }

    private int GetOffsetToEncryptedFileHeader()
    {
      return this.m_variableSignatureLength + 4;
    }

    private int GetTotalSignatureSize()
    {
      return this.GetOffsetToEncryptedFileHeader();
    }

    private long GetRequiredFileSize()
    {
      long num = Convert.ToInt64(this.GetTotalHeaderSize()) + Convert.ToInt64(this.m_encryptedKey.Length) + Convert.ToInt64(this.m_data.DataLength) + Convert.ToInt64(this.m_data.Index.Length + 4);
      foreach (string key in (IEnumerable) this.m_indexes.InnerIndexes.Keys)
      {
        byte[] buffer = ((SecondaryIndex) this.m_indexes.InnerIndexes[(object) key]).GetBuffer();
        num += Convert.ToInt64(8 + buffer.Length);
      }
      return num + num / 20L;
    }

    private unsafe void FlushToStream(Stream stream)
    {
      if (stream == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (stream));
      stream.SetLength(this.GetRequiredFileSize());
      BinaryWriter binaryWriter1 = new BinaryWriter(stream);
      this.m_encAlg.GenerateIV();
      byte[] iv = this.m_encAlg.IV;
      int dataLength = this.m_data.DataLength;
      stream.Seek((long) this.GetTotalHeaderSize(), SeekOrigin.Begin);
      binaryWriter1.Write(this.m_encryptedKey);
      binaryWriter1.Write(iv);
      long position = stream.Position;
      using (BinaryWriter binaryWriter2 = new BinaryWriter((Stream) new MemoryStream()))
      {
        binaryWriter2.Write(this.m_data.Index.Length / 4);
        binaryWriter2.Write(this.m_data.Index);
        binaryWriter2.Write(this.m_indexes.Count);
        foreach (string key in (IEnumerable) this.m_indexes.InnerIndexes.Keys)
        {
          SecondaryIndex innerIndex = (SecondaryIndex) this.m_indexes.InnerIndexes[(object) key];
          int lastIndex = innerIndex.LastIndex;
          binaryWriter2.Write(lastIndex);
          int initialSize = SecondaryIndexDefinition.GetByName(key).InitialSize;
          if (lastIndex + 1 < initialSize)
          {
            binaryWriter2.Write(initialSize);
            InfoCardTrace.Assert(initialSize * sizeof (SecondaryIndexItem) <= innerIndex.GetBuffer().Length, "Buffer length is at least min capacity");
            binaryWriter2.Write(innerIndex.GetBuffer(), 0, initialSize * sizeof (SecondaryIndexItem));
          }
          else
          {
            binaryWriter2.Write(lastIndex + 1);
            binaryWriter2.Write(innerIndex.GetBuffer(), 0, (lastIndex + 1) * sizeof (SecondaryIndexItem));
          }
        }
        binaryWriter2.Flush();
        binaryWriter2.Seek(0, SeekOrigin.Begin);
        this.EncryptData(iv, binaryWriter2.BaseStream, binaryWriter1.BaseStream);
      }
      int int32 = Convert.ToInt32(stream.Position - position);
      int num = int32 + this.m_data.DataLength + this.GetTotalHeaderSize() + iv.Length + this.m_encryptedKey.Length;
      binaryWriter1.Write(this.m_data.Data, 0, this.m_data.DataLength);
      stream.Seek(0L, SeekOrigin.Begin);
      binaryWriter1.Flush();
      fixed (byte* numPtr = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
      {
        ((EncryptedFileStoreHeader*) numPtr)->DataSize = dataLength;
        ((EncryptedFileStoreHeader*) numPtr)->Version = 12U;
        ((EncryptedFileStoreHeader*) numPtr)->Size = num;
        ((EncryptedFileStoreHeader*) numPtr)->IndexSize = int32;
      }
      binaryWriter1.Write(this.m_header);
      stream.SetLength(Convert.ToInt64(num));
      binaryWriter1.Flush();
      this.SignStream(stream);
    }

    private unsafe void SignStream(Stream input)
    {
      if (input == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (input));
      long position = input.Position;
      this.m_encAlg.GenerateIV();
      byte[] numArray = this.SignDigest(this.m_encAlg.IV, this.CreateStreamDigest(input));
      byte[] buffer = new byte[this.GetTotalSignatureSize()];
      fixed (byte* numPtr = &buffer[0])
        ((SignatureHeader*) numPtr)->SignatureSize = this.m_variableSignatureLength;
      Array.Copy((Array) numArray, 0, (Array) buffer, 4, numArray.Length);
      input.Seek(0L, SeekOrigin.Begin);
      input.Write(buffer, 0, buffer.Length);
      InfoCardTrace.Assert(this.m_variableSignatureLength >= numArray.Length, "Generated signature should be less than signature length");
      input.Seek(position, SeekOrigin.Begin);
    }

    private byte[] CreateStreamDigest(Stream input)
    {
      input.Seek((long) this.GetOffsetToEncryptedFileHeader(), SeekOrigin.Begin);
      byte[] data = new byte[Convert.ToInt32((input.Length / 4096L + 1L) * (long) HashUtility.HashBufferLength)];
      int dataIndex = 0;
      byte[] numArray = new byte[4096];
      int dataToHashSize;
      do
      {
        dataToHashSize = input.Read(numArray, 0, numArray.Length);
        if (dataToHashSize > 0)
        {
          HashUtility.SetHashValue(data, dataIndex, numArray, 0, dataToHashSize);
          dataIndex += HashUtility.HashBufferLength;
        }
      }
      while (dataToHashSize == numArray.Length);
      return data;
    }

    private byte[] SignDigest(byte[] iv, byte[] digest)
    {
      byte[] numArray = new byte[this.m_variableSignatureLength];
      using (MemoryStream memoryStream1 = new MemoryStream(digest))
      {
        using (MemoryStream memoryStream2 = new MemoryStream(digest.Length))
        {
          this.EncryptData(iv, (Stream) memoryStream1, (Stream) memoryStream2);
          Array.Copy((Array) memoryStream2.GetBuffer(), Convert.ToInt32(memoryStream2.Position - 1L) - iv.Length, (Array) numArray, 0, iv.Length);
          Array.Copy((Array) iv, 0, (Array) numArray, iv.Length, iv.Length);
          return numArray;
        }
      }
    }

    private void ValidateSignature(Stream input)
    {
      if (input == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (input));
      long position = input.Position;
      byte[] buffer = new byte[this.m_variableSignatureLength];
      byte[] numArray1 = this.AllocateIvBuffer();
      input.Seek(20L, SeekOrigin.Begin);
      input.Read(numArray1, 0, numArray1.Length);
      byte[] numArray2 = this.SignDigest(numArray1, this.CreateStreamDigest(input));
      input.Seek(4L, SeekOrigin.Begin);
      input.Read(buffer, 0, buffer.Length);
      for (int index = 0; index < buffer.Length; ++index)
      {
        if ((int) buffer[index] != (int) numArray2[index])
          throw InfoCardTrace.ThrowHelperError((Exception) new CorruptStoreException(SR.GetString("StoreSignatureNotValid")));
      }
      input.Seek(position, SeekOrigin.Begin);
    }

    protected unsafe void LoadFrom(Stream stream)
    {
      if (stream == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (stream));
      stream.Seek(0L, SeekOrigin.Begin);
      BinaryReader binaryReader1 = (BinaryReader) new InfoCardBinaryReader(stream);
      this.m_header = new byte[this.GetTotalHeaderSize()];
      binaryReader1.Read(this.m_header, 0, this.m_header.Length);
      fixed (byte* numPtr1 = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
      {
        if (11U != ((EncryptedFileStoreHeader*) numPtr1)->Version && 12U != ((EncryptedFileStoreHeader*) numPtr1)->Version)
        {
          CorruptStoreException corruptStoreException = new CorruptStoreException(SR.GetString("StoreVersionNotSupported", (object) ((EncryptedFileStoreHeader*) numPtr1)->Version));
          InfoCardTrace.TraceAndLogException((Exception) corruptStoreException);
          throw InfoCardTrace.ThrowHelperError((Exception) corruptStoreException);
        }
        if (12U == ((EncryptedFileStoreHeader*) numPtr1)->Version)
        {
          this.m_encryptedKey = new byte[((EncryptedFileStoreHeader*) numPtr1)->KeyBlockV2.KeyDataSize];
          binaryReader1.Read(this.m_encryptedKey, 0, ((EncryptedFileStoreHeader*) numPtr1)->KeyBlockV2.KeyDataSize);
        }
        // ISSUE: __unpin statement
        __unpin(numPtr1);
        fixed (byte* numPtr2 = &this.m_header[0])
        {
          if (this.m_variableSignatureLength != ((SignatureHeader*) numPtr2)->SignatureSize)
            throw InfoCardTrace.ThrowHelperError((Exception) new CorruptStoreException(SR.GetString("StoreSignatureNotValid")));
        }
        this.ObtainDataKeyFromHeader();
        this.ValidateSignature(stream);
        fixed (byte* numPtr2 = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
        {
          byte[] numArray = this.AllocateIvBuffer();
          byte[] masterIndex;
          using (MemoryStream memoryStream1 = new MemoryStream())
          {
            binaryReader1.Read(numArray, 0, numArray.Length);
            byte[] buffer1 = binaryReader1.ReadBytes(((EncryptedFileStoreHeader*) numPtr2)->IndexSize);
            using (MemoryStream memoryStream2 = new MemoryStream(buffer1))
            {
              this.DecryptData(numArray, (Stream) memoryStream2, (Stream) memoryStream1);
              Array.Clear((Array) buffer1, 0, buffer1.Length);
            }
            memoryStream1.Seek(0L, SeekOrigin.Begin);
            BinaryReader binaryReader2 = (BinaryReader) new InfoCardBinaryReader((Stream) memoryStream1);
            int num1 = binaryReader2.ReadInt32();
            InfoCardTrace.Assert(num1 > 0, "MasterIndexCount Invalid");
            masterIndex = binaryReader2.ReadBytes(num1 * 4);
            InfoCardTrace.Assert((uint) binaryReader2.ReadInt32() <= (uint) this.m_indexes.Count, "SecondaryIndexCount Invalid");
            foreach (string key in (IEnumerable) this.m_indexes.InnerIndexes.Keys)
            {
              int lastIndex = binaryReader2.ReadInt32();
              int num2 = binaryReader2.ReadInt32();
              byte[] buffer2 = new byte[Utility.CalculateIncreaseByPercent(num2 * sizeof (SecondaryIndexItem), sizeof (SecondaryIndexItem), SecondaryIndexDefinition.GetByName(key).GrowthFactor)];
              binaryReader2.Read(buffer2, 0, num2 * sizeof (SecondaryIndexItem));
              this.m_indexes.SetBuffer(key, buffer2, lastIndex);
            }
          }
          using (MemoryStream memoryStream = new MemoryStream(Utility.CalculateIncreaseByPercent(Convert.ToInt32(binaryReader1.BaseStream.Length - binaryReader1.BaseStream.Position), 1, 5)))
          {
            byte[] buffer1 = new byte[256];
            int num = 0;
            int count;
            do
            {
              count = binaryReader1.Read(buffer1, 0, buffer1.Length);
              memoryStream.Write(buffer1, 0, count);
              num += count;
            }
            while (count == buffer1.Length);
            byte[] buffer2 = memoryStream.GetBuffer();
            if (num == 0)
              buffer2 = new byte[2048];
            this.m_data = new IndexedDataBuffer(masterIndex, buffer2, ((EncryptedFileStoreHeader*) numPtr2)->DataSize, (DataSource) this);
          }
        }
      }
    }

    protected virtual void SwapFileWithShadow()
    {
      this.CloseFiles();
      this.OnSwapFileWithShadow();
      try
      {
        this.CreateDirAndFiles();
      }
      catch
      {
        this.CloseFiles();
        throw;
      }
    }

    private unsafe void EncryptAndSaveDPAPIKeyToHeader()
    {
      DataBlob dataBlob1 = new DataBlob();
      DataBlob dataBlob2 = new DataBlob();
      byte[] data = new byte[32 + HashUtility.HashBufferLength];
      this.UnprotectKey();
      try
      {
        Array.Copy((Array) this.m_key, 0, (Array) data, 0, 32);
        HashUtility.SetHashValue(data, 32, this.m_key, 0, 32);
        fixed (byte* numPtr1 = &data[0])
        {
          DataBlob dataBlob3;
          dataBlob3.pbData = new IntPtr((void*) numPtr1);
          dataBlob3.cbData = data.Length;
          try
          {
            if (!NativeMethods.CryptProtectData(new IntPtr((void*) &dataBlob3), (string) null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 65, new IntPtr((void*) &dataBlob1)))
              throw InfoCardTrace.ThrowHelperError((Exception) new Win32Exception(Marshal.GetLastWin32Error(), SR.GetString("StoreCryptProtectDataFailed")));
            using (new SystemIdentity(true))
            {
              if (!NativeMethods.CryptProtectData(new IntPtr((void*) &dataBlob1), (string) null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 65, new IntPtr((void*) &dataBlob2)))
                throw InfoCardTrace.ThrowHelperError((Exception) new Win32Exception(Marshal.GetLastWin32Error(), SR.GetString("StoreCryptProtectDataAsSystemFailed")));
            }
            fixed (byte* numPtr2 = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
            {
              ((EncryptedFileStoreHeader*) numPtr2)->KeyBlockV2.KeyDataOffset = 0;
              ((EncryptedFileStoreHeader*) numPtr2)->KeyBlockV2.KeyDataSize = dataBlob2.cbData;
              this.m_encryptedKey = new byte[dataBlob2.cbData];
              for (int index = 0; index < dataBlob2.cbData; ++index)
                this.m_encryptedKey[index] = *(byte*) ((IntPtr) dataBlob2.pbData.ToPointer() + index);
            }
          }
          finally
          {
            Exception e = (Exception) null;
            if (IntPtr.Zero != dataBlob1.pbData)
            {
              Utility.ClearUnsafeMemory(dataBlob1.pbData, dataBlob1.cbData);
              if (IntPtr.Zero != NativeMethods.LocalFree(dataBlob1.pbData))
                e = (Exception) new Win32Exception(Marshal.GetLastWin32Error());
            }
            if (IntPtr.Zero != dataBlob2.pbData)
            {
              Utility.ClearUnsafeMemory(dataBlob2.pbData, dataBlob2.cbData);
              if (IntPtr.Zero != NativeMethods.LocalFree(dataBlob2.pbData))
                e = (Exception) new Win32Exception(Marshal.GetLastWin32Error());
            }
            if (e != null)
              throw InfoCardTrace.ThrowHelperError(e);
          }
        }
      }
      finally
      {
        this.ProtectKey();
        Array.Clear((Array) data, 0, data.Length);
      }
    }

    private void ObtainDataKeyFromHeader()
    {
      try
      {
        byte[] dataKeyFromDpapi = this.TryObtainDataKeyFromDPAPI();
        if (dataKeyFromDpapi == null)
          throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreUnableToGetStoreKeyFromDPAPI")));
        this.m_key = dataKeyFromDpapi;
        this.m_keyProtected = false;
        this.ProtectKey();
      }
      catch (Exception ex)
      {
        if (!InfoCardTrace.IsFatal(ex))
          throw InfoCardTrace.ThrowHelperError((Exception) new InvalidStoreProtectionKeyException());
        throw;
      }
    }

    private unsafe byte[] TryObtainDataKeyFromDPAPI()
    {
      DataBlob dataBlob1 = new DataBlob();
      DataBlob dataBlob2 = new DataBlob();
      fixed (byte* numPtr = &this.m_header[this.GetOffsetToEncryptedFileHeader()])
      {
        if (11U == ((EncryptedFileStoreHeader*) numPtr)->Version && ((EncryptedFileStoreHeader*) numPtr)->KeyBlock.KeyType != 0)
          throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreFileNotProtectedWithDPAPI")));
        byte[] numArray = (byte[]) null;
        GCHandle gcHandle = new GCHandle();
        try
        {
          DataBlob dataBlob3;
          if (((EncryptedFileStoreHeader*) numPtr)->Version == 12U)
          {
            gcHandle = GCHandle.Alloc((object) this.m_encryptedKey, GCHandleType.Pinned);
            dataBlob3.pbData = gcHandle.AddrOfPinnedObject();
            dataBlob3.cbData = ((EncryptedFileStoreHeader*) numPtr)->KeyBlockV2.KeyDataSize;
          }
          else
          {
            dataBlob3.pbData = new IntPtr((void*) &((EncryptedFileStoreHeader*) numPtr)->KeyBlock.EncryptedKey);
            dataBlob3.cbData = ((EncryptedFileStoreHeader*) numPtr)->KeyBlock.EncryptedKeySize;
            ((EncryptedFileStoreHeader*) numPtr)->KeyBlockV2.KeyDataOffset = 0;
            ((EncryptedFileStoreHeader*) numPtr)->KeyBlockV2.KeyDataSize = dataBlob3.cbData;
            this.m_encryptedKey = new byte[dataBlob3.cbData];
            for (int index = 0; index < dataBlob3.cbData; ++index)
              this.m_encryptedKey[index] = *(byte*) ((IntPtr) dataBlob3.pbData.ToPointer() + index);
          }
          using (new SystemIdentity(true))
          {
            if (!NativeMethods.CryptUnprotectData(new IntPtr((void*) &dataBlob3), (StringBuilder) null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, new IntPtr((void*) &dataBlob2)))
              throw InfoCardTrace.ThrowHelperError((Exception) new Win32Exception(Marshal.GetLastWin32Error(), SR.GetString("StoreCryptUnprotectDataAsSystemFailed")));
          }
          if (!NativeMethods.CryptUnprotectData(new IntPtr((void*) &dataBlob2), (StringBuilder) null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, new IntPtr((void*) &dataBlob1)))
            throw InfoCardTrace.ThrowHelperError((Exception) new Win32Exception(Marshal.GetLastWin32Error(), SR.GetString("StoreCryptUnprotectDataFailed")));
          InfoCardTrace.Assert(dataBlob1.cbData == 32 + HashUtility.HashBufferLength, "The data size returned by CryptUnprotectData is invalid or corrupt.");
          numArray = new byte[32];
          Marshal.Copy(dataBlob1.pbData, numArray, 0, 32);
          byte[] data = new byte[HashUtility.HashBufferLength];
          HashUtility.SetHashValue(data, 0, numArray, 0, 32);
          for (int index = 0; index < data.Length; ++index)
          {
            if ((int) data[index] != (int) *(byte*) ((IntPtr) dataBlob1.pbData.ToPointer() + (32 + index)))
              throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreDecryptedKeyIsNotValid")));
          }
          return numArray;
        }
        catch
        {
          if (numArray != null)
            Array.Clear((Array) numArray, 0, numArray.Length);
          throw;
        }
        finally
        {
          if (gcHandle.IsAllocated)
            gcHandle.Free();
          if (IntPtr.Zero != dataBlob2.pbData)
          {
            Utility.ClearUnsafeMemory(dataBlob2.pbData, dataBlob2.cbData);
            NativeMethods.LocalFree(dataBlob2.pbData);
          }
          if (IntPtr.Zero != dataBlob1.pbData)
          {
            Utility.ClearUnsafeMemory(dataBlob1.pbData, dataBlob1.cbData);
            NativeMethods.LocalFree(dataBlob1.pbData);
          }
        }
      }
    }

    private bool LogIfAclsTampered(FileSystemInfo fileSysInfo)
    {
      bool condition = true;
      try
      {
        FileSystemSecurity accessControl;
        if (fileSysInfo is DirectoryInfo)
        {
          accessControl = (FileSystemSecurity) ((DirectoryInfo) fileSysInfo).GetAccessControl(AccessControlSections.Access | AccessControlSections.Owner);
        }
        else
        {
          InfoCardTrace.Assert(fileSysInfo is FileInfo, "Only fileinfo possible");
          accessControl = (FileSystemSecurity) ((FileInfo) fileSysInfo).GetAccessControl(AccessControlSections.Access | AccessControlSections.Owner);
        }
        condition = this.LogIfAclsTamperedHelper(accessControl);
      }
      catch (UnauthorizedAccessException ex)
      {
        InfoCardTrace.Assert(condition, "ACL must have been tampered with");
      }
      if (condition)
        InfoCardTrace.TraceAndLogException((Exception) new DataAccessException(SR.GetString("StoreAclsTamperedWith")));
      return condition;
    }

    private bool LogIfAclsTamperedHelper(FileSystemSecurity fs)
    {
      if (SystemIdentity.LsaIdentityReference != fs.GetOwner(typeof (SecurityIdentifier)))
        return true;
      AuthorizationRuleCollection accessRules = fs.GetAccessRules(true, true, typeof (SecurityIdentifier));
      bool flag = fs is DirectorySecurity;
      foreach (FileSystemAccessRule systemAccessRule in (ReadOnlyCollectionBase) accessRules)
      {
        if ((!(SystemIdentity.LsaIdentityReference == systemAccessRule.IdentityReference) || FileSystemRights.FullControl != systemAccessRule.FileSystemRights || systemAccessRule.AccessControlType != AccessControlType.Allow) && (!flag || !((IdentityReference) FileDataSource.AdministratorSid == systemAccessRule.IdentityReference) || (systemAccessRule.AccessControlType != AccessControlType.Allow || (FileSystemRights.ReadData | FileSystemRights.DeleteSubdirectoriesAndFiles | FileSystemRights.Synchronize) != systemAccessRule.FileSystemRights)))
          return true;
      }
      return false;
    }

    private static T CreateSecurityDescriptor<T>() where T : FileSystemSecurity, new()
    {
      T obj = new T();
      obj.SetOwner(SystemIdentity.LsaIdentityReference);
      foreach (FileSystemAccessRule accessRule in (ReadOnlyCollectionBase) obj.GetAccessRules(true, true, typeof (SecurityIdentifier)))
        obj.RemoveAccessRuleAll(accessRule);
      obj.AddAccessRule(new FileSystemAccessRule(SystemIdentity.LsaIdentityReference, FileSystemRights.FullControl, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Allow));
      if ((object) obj is DirectorySecurity)
        obj.AddAccessRule(new FileSystemAccessRule((IdentityReference) FileDataSource.AdministratorSid, FileSystemRights.ReadData | FileSystemRights.DeleteSubdirectoriesAndFiles, AccessControlType.Allow));
      obj.SetAccessRuleProtection(true, false);
      return obj;
    }

    private void SetupProvider()
    {
      this.m_provider = SafeRsaProviderHandle.Construct();
    }

    private byte[] AllocateIvBuffer()
    {
      InfoCardTrace.Assert(16 == this.m_encAlg.IV.Length, "Must be equal");
      InfoCardTrace.Assert(16 == this.m_encAlg.IV.Length, "Must be equal");
      return new byte[this.m_encAlg.IV.Length];
    }

    private static void ResilientDelete(FileInfo toDelete)
    {
      int millisecondsTimeout = 10;
      bool flag = true;
      Exception inner = (Exception) null;
      do
      {
        if (!flag)
        {
          Thread.Sleep(millisecondsTimeout);
          millisecondsTimeout *= 2;
        }
        try
        {
          toDelete.Delete();
          flag = true;
        }
        catch (IOException ex)
        {
          inner = (Exception) ex;
          flag = false;
        }
      }
      while (!flag && millisecondsTimeout <= 500);
      if (!flag)
        throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreFileInUse"), inner));
    }

    private static void ResilientMove(FileInfo fileFrom, FileInfo fileTo)
    {
      int millisecondsTimeout = 10;
      bool flag = true;
      do
      {
        if (!flag)
        {
          Thread.Sleep(millisecondsTimeout);
          millisecondsTimeout *= 2;
        }
        try
        {
          fileFrom.MoveTo(fileTo.FullName);
          flag = true;
        }
        catch (IOException ex)
        {
          flag = false;
        }
      }
      while (!flag && millisecondsTimeout <= 500);
      if (flag)
        return;
      InfoCardTrace.FailFast(SR.GetString("StoreFileInUse"));
    }

    private static FileStream ResilientOpen(
      FileInfo toOpen,
      FileMode mode,
      FileAccess access)
    {
      int millisecondsTimeout = 10;
      bool flag = true;
      Exception inner = (Exception) null;
      FileStream fileStream = (FileStream) null;
      do
      {
        if (!flag)
        {
          Thread.Sleep(millisecondsTimeout);
          millisecondsTimeout *= 2;
        }
        try
        {
          fileStream = toOpen.Open(mode, access, FileShare.None);
          flag = true;
        }
        catch (IOException ex)
        {
          inner = (Exception) ex;
          flag = false;
        }
      }
      while (!flag && millisecondsTimeout <= 500);
      if (!flag)
        throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreFileInUse"), inner));
      return fileStream;
    }

    internal static SymmetricAlgorithm CreateEncryptionAlg()
    {
      RijndaelManaged rijndaelManaged = new RijndaelManaged();
      rijndaelManaged.Mode = CipherMode.CBC;
      rijndaelManaged.KeySize = 256;
      rijndaelManaged.BlockSize = 128;
      return (SymmetricAlgorithm) rijndaelManaged;
    }
  }
}
